package org.example.page;

import io.ebean.typequery.IQueryBean;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 封装排序请求参数。
 */
public class SortParam implements Serializable {

    static Logger logger = LoggerFactory.getLogger(SortParam.class);


    protected static final List<Order> DEFAULT_SORT = Collections.emptyList(); // 默认不排序

    /**
     * 排序规则列表
     */
    private List<Order> sort;

    /**
     * 使用默认排序 (不排序) 创建 SortParam
     */
    public SortParam() {
        this(DEFAULT_SORT);
    }

    /**
     * 使用指定的排序规则列表创建 SortParam
     *
     * @param sort 排序规则列表 (可以为 null 或空)
     */
    public SortParam(List<Order> sort) {
        // 防御性拷贝，并处理 null
        this.sort = (sort == null) ? DEFAULT_SORT : Collections.unmodifiableList(new ArrayList<>(sort));
    }

    /**
     * 静态工厂方法 - 使用 Order 对象列表创建
     *
     * @param sort 排序规则列表
     * @return SortParam 实例
     */
    public static SortParam by(List<Order> sort) {
        return new SortParam(sort);
    }

    /**
     * 静态工厂方法 - 使用可变参数 Order 对象创建
     *
     * @param orders 排序规则 (可变参数)
     * @return SortParam 实例
     */
    public static SortParam by(Order... orders) {
        return new SortParam(Arrays.asList(orders));
    }

    public void setSort(List<String> sort) {
        this.sort = parseSortStrings(sort);
    }

    /**
     * 获取排序规则列表 (返回的是不可变视图)
     *
     * @return 排序规则列表
     */
    public List<Order> getSort() {
        return sort;
    }

    /**
     * 检查是否有排序规则
     *
     * @return 如果设置了排序规则则返回 true
     */
    public boolean hasSort() {
        return sort != null && !sort.isEmpty();
    }

    /**
     * 生成用于 SQL 查询的 ORDER BY 子句的内容。
     * 例如："property1 ASC, property2 DESC"
     * 如果没有定义排序规则，则返回空字符串 ""。
     * 注意：此方法不包含 "ORDER BY" 关键字本身。
     *
     * @return ORDER BY 子句的内容字符串，或者在没有排序时返回空字符串。
     */
    public String getOrderByClause() {
        if (!hasSort()) {
            return ""; // 没有排序规则，返回空字符串
        }
        // 使用 Stream API 将 Order 列表转换为 "property direction" 格式，并用逗号连接
        return this.sort.stream()
                .map(order -> order.property() + " " + order.direction()) // Order 是 record，直接访问属性
                .collect(Collectors.joining(", "));
    }


    @Override
    public String toString() {
        if (sort.isEmpty()) {
            return "UNSORTED";
        }
        return sort.stream().map(Order::toString).collect(Collectors.joining(", "));
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        SortParam sortParam = (SortParam) o;
        return Objects.equals(sort, sortParam.sort);
    }

    @Override
    public int hashCode() {
        return Objects.hash(sort);
    }

    /**
     * 应用排序规则到 Ebean Query 该方法依赖于 IQueryBean 接口，
     * 该接口是 Ebean 提供的用于构建查询的接口。
     * 它允许我们在查询构建过程中动态地添加排序规则，而无需在查询构建后再添加。
     * 这个方法会自动设置查询的 orderBy 属性，
     *
     * @param query
     * @param <T>
     * @param <R>
     */
    public <T, R extends IQueryBean<T, R>> void applySort(IQueryBean<T, R> query) {
        if (hasSort()) {
            query.orderBy(getOrderByClause());
        }
    }

    // --- 内部类：用于封装排序信息 (保持不变) ---

    /**
     * 解析排序字符串列表，使用 forEach 实现逻辑。
     *
     * @param sortStrings 包含排序字符串的列表，例如 [" name , asc ", " age, DESC ", " birthy ", "  ", "id,asc,extra"]
     * @return 解析后的 Order 对象列表。
     * @throws IllegalArgumentException 如果排序字符串格式无效（逗号分割超过2部分）。
     */
    public static List<Order> parseSortStrings(List<String> sortStrings) {
        if (sortStrings == null || sortStrings.isEmpty()) {
            return Collections.emptyList(); // 返回空列表，如果输入为空
        }

        List<Order> orders = new ArrayList<>(); // 用于存储结果

        sortStrings.forEach(s -> {
            if (s == null || s.trim().isEmpty()) {
                logger.debug("跳过空或仅包含空格的排序字符串");
                return; // continue 的效果，跳过当前循环
            }

            String[] parts = s.split(",");
            String property = parts[0].trim(); // 获取属性名并 trim

            // --- 根据 parts 长度和 property 是否为空执行逻辑 ---

            if (property.isEmpty()) {
                logger.debug("跳过属性名为空的排序字符串: \"" + s + "\"");
                return; // 属性名为空，跳过
            }

            switch (parts.length) {
                case 1:
                    // 只有属性名，默认为 ASC
                    logger.debug("解析: \"" + s + "\" -> " + property + " ASC (默认)");
                    orders.add(Order.asc(property));
                    break;
                case 2:
                    // 包含属性名和方向
                    String directionString = parts[1].trim(); // 获取方向字符串并 trim
                    // 这里可以增加对 directionString 是否为空的判断，如果为空可以按默认 ASC 处理或报错
                    // if (directionString.isEmpty()) { orders.add(Order.asc(property)); break; }
                    Direction direction = Direction.fromString(directionString); // 解析方向
                    logger.debug("解析: \"" + s + "\" -> " + property + " " + direction);
                    orders.add(new Order(property, direction));
                    break;
                default:
                    // 超过 2 部分，格式错误
                    System.err.println("错误：无效的排序格式: \"" + s + "\" (逗号分割超过2部分)");
                    throw new IllegalArgumentException("Invalid sort format: \"" + s + "\" (more than 2 parts)");
            }
        });

        return orders;
    }

    /**
     * 排序方向枚举
     */
    public enum Direction {
        ASC, DESC;

        public static Direction fromString(String value) {
            if (StringUtils.isBlank(value)) {
                return Direction.ASC;
            }
            try {
                return Direction.valueOf(value.toUpperCase());
            } catch (Exception e) {
                throw new IllegalArgumentException(String.format(
                        "Invalid value '%s' for orders direction! Must be 'asc' or 'desc' (case insensitive).", value), e);
            }
        }
    }

    /**
     * 单个排序规则对象 (属性 + 方向)
     */
    public record Order(String property, Direction direction) implements Serializable {
        private static final Direction DEFAULT_DIRECTION = Direction.ASC;

        public Order {
            Objects.requireNonNull(property, "Property must not be null!");
            if (property.trim().isEmpty()) {
                throw new IllegalArgumentException("Property must not be empty!");
            }
            Objects.requireNonNull(direction, "Direction must not be null!");
        }

        public static Order asc(String property) {
            return new Order(property, Direction.ASC);
        }

        public static Order desc(String property) {
            return new Order(property, Direction.DESC);
        }

        public static Order by(String property) {
            return new Order(property, DEFAULT_DIRECTION);
        }

        public Order reverse() {
            return new Order(this.property, this.direction == Direction.ASC ? Direction.DESC : Direction.ASC);
        }

        @Override
        public String toString() {
            return String.format("%s: %s", property, direction);
        }
    }
}